package gui;

import schedule.Event;

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

import javax.swing.*;
import com.jgoodies.forms.factories.*;
import com.jgoodies.forms.layout.*;
import com.thirdnf.ResourceScheduler.AbstractScheduleModel;
import com.thirdnf.ResourceScheduler.Resource;
import com.thirdnf.ResourceScheduler.ResourceVisitor;
import org.joda.time.*;

/**
 * Represente la boite de dialogue pour les manipulations sur les evenements
 * @author Stanislas KOBAK / Celine BARILLERE
 *
 */
@SuppressWarnings("serial")
public class AppointmentDialog extends JDialog
{
    private JPanel dialogPane;
    private JPanel contentPanel;
    private JLabel label1;
    private JTextField titleField;
    private JLabel label6;
    private JTextField placeField;
    private JLabel label2;
    private JComboBox startTimeCombo;
    private JLabel label3;
    private JPanel panel1;
    private JSpinner durationSpinner;
    private JLabel label5;
    private JLabel label4;
    private JComboBox resourceCombo;
    private JPanel buttonBar;
    private JButton okButton;
    private JButton cancelButton;
	
    private static final LocalTime StartTime = new LocalTime(8, 0, 0);
    private static final LocalTime EndTime   = new LocalTime(20, 00, 0);
    private static final Duration  Increment = Duration.standardMinutes(15);
    private LocalDate date;
    private MyAppointment appointment;
    private IOkayListener listener;

    /**
     * Transforme la boite de dialogue pour l'ajout d'evenements
     * @param date La date (pour l'affichage par journee) ou la date du premier jour de la semaine (pour l'affichage par semaine) qui est actuellement affichee sur l'emploi du temps
     * @param model Le type d'affichage utilise
     */
    public AppointmentDialog(LocalDate date, AbstractScheduleModel model)
    {
        initComponents();
        this.date = date;
        appointment = null;
        initialize(model);
        setTitle("Add an appointment");
    }
    
    /**
     * Transforme la boite de dialogue pour l'edition d'evenements
     * @param appointment L'evenement a modifie
     * @param model Le type d'affichage utilise
     */
    public AppointmentDialog(MyAppointment appointment, AbstractScheduleModel model)
    {
        initComponents();
        if (model instanceof WeekModel) {
        	this.date = appointment.getDateTime().toLocalDate().dayOfWeek().withMinimumValue();
        }
        else {
        	this.date = appointment.getDateTime().toLocalDate();
        }
        this.appointment = appointment;

        initialize(model);

        titleField.setText(this.appointment.getTitle());
        placeField.setText(this.appointment.getPlace());
        resourceCombo.setSelectedItem(this.appointment.getResource());
        startTimeCombo.setSelectedItem(this.appointment.getDateTime().toLocalTime());
        durationSpinner.setValue((int) (this.appointment.getDuration().getStandardSeconds()/60));

        setTitle("Edit an appointment");
    }


    /**
     * Prepare l'affichage pour les heures et les ressources (un jour de la semaine ou une journee)
     * @param model Le type d'affichage utilise
     */
    private void initialize(final AbstractScheduleModel model)
    {
        // We are using a combo box simply because we are too lazy to try to parse a string and give helpful
        //  error messages.  This is a example after all.
        startTimeCombo.setRenderer(new TimeCellRenderer());
        for (LocalTime time = StartTime; time.compareTo(EndTime) <= 0; time = time.plus(Increment.toPeriod())) {
            startTimeCombo.addItem(time);
        }

        model.visitResources(new ResourceVisitor()
        {
            @Override
            public boolean visitResource(Resource resource)
            {
            	resourceCombo.setRenderer(new ResourceCellRenderer());
                resourceCombo.addItem(resource);
                return true;
            }
        }, date);
    }

    /**
     * Recupere un listener
     * @param listener Le listener
     */
    public void setOkayListener(IOkayListener listener)
    {
        this.listener = listener;
    }

    /**
     * Methode appelee quand l'utilisateur clique sur le bouton OK
     */
    private void handleOkay()
    {
        if (listener != null) {
            String title = titleField.getText().trim();
            String place = placeField.getText().trim();
            Resource resource = (Day) resourceCombo.getSelectedItem();
            LocalTime startTime = (LocalTime) startTimeCombo.getSelectedItem();
            DateTime start = new DateTime(date.year().get(), date.monthOfYear().get(),
                    date.dayOfMonth().get(), startTime.getHourOfDay(),
                    startTime.getMinuteOfHour(), startTime.getSecondOfMinute(), 0);
            int duration = (Integer) durationSpinner.getValue();
            
            Event event = new Event(title, place, start, duration, new ArrayList<String>());

            if (this.appointment == null) {
            	this.appointment = new MyAppointment(event, resource);
            }
            else {
            	this.appointment.setTitle(title);
            	this.appointment.setPlace(place);
            	this.appointment.setResource(resource);
            }
            this.appointment.setDateTime(start);
            this.appointment.setDuration(Duration.standardMinutes(duration));

            listener.handleOkay(this.appointment);
        }

        dispose();
    }

    /**
     * Methode appellee quand l'utilisateur clique sur le bouton Cancel
     */
    private void handleCancelButton()
    {
        dispose();
    }



    public static interface IOkayListener
    {
        void handleOkay(MyAppointment appointment);
    }


    /**
     * Definit la facon d'afficher les heures
     */
    private static class TimeCellRenderer extends DefaultListCellRenderer
    {
        @Override
        public Component getListCellRendererComponent(JList list, Object value,
                                                      int index, boolean isSelected, boolean cellHasFocus)
        {
            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            setText(((LocalTime) value).toString("h:mm a"));

            return this;
        }
    }
    
    /**
     * Definit la facon d'afficher les ressources
     */
    private static class ResourceCellRenderer extends DefaultListCellRenderer
    {
        @Override
        public Component getListCellRendererComponent(JList list, Object value,
                                                      int index, boolean isSelected, boolean cellHasFocus)
        {
            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            setText(((Day) value).getTitle());

            return this;
        }
    }

    /**
     * Initialise les composants de la boite de dialogue
     */
    private void initComponents() 
    {
        dialogPane = new JPanel();
        contentPanel = new JPanel();
        label1 = new JLabel();
        titleField = new JTextField();
        label6 = new JLabel();
        placeField = new JTextField();
        label2 = new JLabel();
        startTimeCombo = new JComboBox();
        label3 = new JLabel();
        panel1 = new JPanel();
        durationSpinner = new JSpinner();
        label5 = new JLabel();
        label4 = new JLabel();
        resourceCombo = new JComboBox();
        buttonBar = new JPanel();
        okButton = new JButton();
        cancelButton = new JButton();
        CellConstraints cc = new CellConstraints();

        //======== this ========
        Container contentPane = getContentPane();
        contentPane.setLayout(new BorderLayout());

        //======== dialogPane ========
        {
            dialogPane.setBorder(Borders.DIALOG_BORDER);
            dialogPane.setLayout(new BorderLayout());

            //======== contentPanel ========
            {
                contentPanel.setLayout(new FormLayout(
                    "default, $lcgap, [50dlu,default]:grow",
                    "4*(default, $lgap), default"));

                //---- label1 ----
                label1.setText("Title");
                contentPanel.add(label1, cc.xy(1, 1));
                contentPanel.add(titleField, cc.xy(3, 1));
                
                //---- label6 ----
                label6.setText("Place");
                contentPanel.add(label6, cc.xy(1, 3));
                contentPanel.add(placeField, cc.xy(3, 3));

                //---- label2 ----
                label2.setText("Start Time");
                contentPanel.add(label2, cc.xy(1, 5));
                contentPanel.add(startTimeCombo, cc.xy(3, 5));

                //---- label3 ----
                label3.setText("Duration");
                contentPanel.add(label3, cc.xy(1, 7));

                //======== panel1 ========
                {
                    panel1.setLayout(new FormLayout(
                        "[50dlu,default]:grow, $lcgap, default:grow",
                        "default"));
                    panel1.add(durationSpinner, cc.xy(1, 1));

                    //---- label5 ----
                    label5.setText("minutes");
                    panel1.add(label5, cc.xy(3, 1));
                }
                contentPanel.add(panel1, cc.xy(3, 7));

                //---- label4 ----
                label4.setText("Resource");
                contentPanel.add(label4, cc.xy(1, 9));
                contentPanel.add(resourceCombo, cc.xy(3, 9));

            }
            dialogPane.add(contentPanel, BorderLayout.CENTER);

            //======== buttonBar ========
            {
                buttonBar.setBorder(Borders.BUTTON_BAR_GAP_BORDER);
                buttonBar.setLayout(new FormLayout(
                    "$glue, $button, $rgap, $button",
                    "pref"));

                //---- okButton ----
                okButton.setText("OK");
                okButton.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        handleOkay();
                    }
                });
                buttonBar.add(okButton, cc.xy(2, 1));

                //---- cancelButton ----
                cancelButton.setText("Cancel");
                cancelButton.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        handleCancelButton();
                    }
                });
                buttonBar.add(cancelButton, cc.xy(4, 1));
            }
            dialogPane.add(buttonBar, BorderLayout.SOUTH);
        }
        contentPane.add(dialogPane, BorderLayout.CENTER);
        pack();
        setLocationRelativeTo(getOwner());
    }
}

